package cn.sciento.transfer.infra.datasource.utils;

import cn.sciento.core.convertor.ApplicationContextHelper;
import cn.sciento.core.exception.CommonException;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.util.Assert;

public class AsyncExecutionTemplate {
  private static final Logger LOGGER = LoggerFactory.getLogger(AsyncExecutionTemplate.class);
  
  public static AsyncTaskExecutor findAsyncTaskExecutor(String asyncTaskExecutorInstanceName) {
    return (AsyncTaskExecutor)ApplicationContextHelper.getContext().getBean(asyncTaskExecutorInstanceName, AsyncTaskExecutor.class);
  }
  
  public static <T> T asyncDoExecuteAndAwait(AsyncTaskExecutor asyncTaskExecutor, AsyncExecution<T> asyncExecution) {
    Assert.notNull(asyncTaskExecutor, "async task executor cannot be null");
    Assert.notNull(asyncExecution, "async execution callback cannot be null");
    Future<T> future = asyncTaskExecutor.submit(() -> asyncExecution.doAsyncExecution());
    try {
      return future.get();
    } catch (Exception ex) {
      LOGGER.error("async do execute and await with error: ", ex);
      throw new CommonException(ex);
    } 
  }
  
  public static <T> Future<T> asyncDoExecute(AsyncTaskExecutor asyncTaskExecutor, AsyncExecution<T> asyncExecution) {
    Assert.notNull(asyncTaskExecutor, "async task executor cannot be null");
    Assert.notNull(asyncExecution, "async execution callback cannot be null");
    return asyncTaskExecutor.submit(() -> asyncExecution.doAsyncExecution());
  }
  
  @FunctionalInterface
  public static interface AsyncExecution<T> {
    T doAsyncExecution();
  }
}
